/*
 * Copyright 2010 Clavid AG
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.clavid.example.oauth.suisseid;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;
import net.oauth.client.OAuthClient;
import net.oauth.client.httpclient3.HttpClient3;

/**
 * Utility class for accessing the Clavid SuisseID OAUTH service.
 * <p>
 * @version $Id: ClavidOAuthSuisseID.java 6 2010-05-17 09:19:49Z telbie $
 */
public class ClavidOAuthSuisseID {

  private static final String SUISSE_ID_ATTRIBUTE_PREFIX = "suisseid_";
  
  public static final String SUISSE_ID_NUMBER = SUISSE_ID_ATTRIBUTE_PREFIX + "number";
  public static final String SUISSE_ID_EMAIL  = SUISSE_ID_ATTRIBUTE_PREFIX + "email";
  public static final String SUISSE_ID_NAME   = SUISSE_ID_ATTRIBUTE_PREFIX + "name";

  public static final String OAUTH_TOKEN = OAuth.OAUTH_TOKEN;
  
  private static final String CLAVID_OAUTH_SERVICE_URL = "https://www.clavid.com/provider/oauth";

  private OAuthServiceProvider serviceProvider = new OAuthServiceProvider(
                                      CLAVID_OAUTH_SERVICE_URL + "/request_token",
                                      CLAVID_OAUTH_SERVICE_URL + "/authorize",
                                      CLAVID_OAUTH_SERVICE_URL + "/access_token");
  
  private String consumerKey = null;
  private String consumerSecret = null;
  private String callbackUrl = null;
  private String token = null;
  private String tokenSecret = null;
  private String authorizationURL = null;
  private Map<String,String>    requestedAttributes = new HashMap<String,String>();
  private Map<String,String>    attributes = new HashMap<String,String>();

  private ClavidOAuthSuisseID(String consumerKey, String consumerSecret) {
    this.consumerKey = consumerKey;
    this.consumerSecret = consumerSecret;
    requestedAttributes.put("clavid_service", "suisseid");
  }

  public ClavidOAuthSuisseID(String consumerKey, String consumerSecret, String callbackUrl) {
    this(consumerKey, consumerSecret);
    this.callbackUrl = callbackUrl;
  }
  
  public ClavidOAuthSuisseID(String consumerKey, String consumerSecret, String token, String tokenSecret) {
    this(consumerKey, consumerSecret);
    this.token = token;
    this.tokenSecret = tokenSecret;
  }
  
  public void setUserLanguage(Locale language) {
    if (language != null) {
      requestedAttributes.put("user_language", language.getLanguage());
    }
  }

  public void setRequiredAttribute(String attributeName) {
    requestedAttributes.put(attributeName, "required");
  }

  public void setOptionalAttribute(String attributeName) {
    requestedAttributes.put(attributeName, "optional");
  }

  public String getAttribute(String attributeName) {
    return attributes.get(attributeName);
  }
  
  private OAuthAccessor getOAuthAccessor() {
    String oauthCallback = callbackUrl;
    if (oauthCallback == null || oauthCallback.trim().length() <= 0) {
      oauthCallback = "oob";
    }
    OAuthConsumer consumer = new OAuthConsumer(oauthCallback, consumerKey, consumerSecret, serviceProvider);
    OAuthAccessor accessor = new OAuthAccessor(consumer);
    return accessor;
  }

  public void callRequestToken() throws IOException {
    try {
      OAuthClient client = new OAuthClient(new HttpClient3());
      OAuthAccessor accessor = getOAuthAccessor();

      List<OAuth.Parameter> parameters = OAuth.newList(OAuth.OAUTH_CALLBACK, accessor.consumer.callbackURL);
      for(Map.Entry<String, String> entry : requestedAttributes.entrySet()) {
        parameters.add(new OAuth.Parameter(entry.getKey(), entry.getValue()));
      }
      client.getRequestToken(accessor, null, parameters);
      token = accessor.requestToken;
      tokenSecret = accessor.tokenSecret;
      authorizationURL = OAuth.addParameters(serviceProvider.userAuthorizationURL, OAuth.OAUTH_TOKEN, token);
    } catch (Exception e) {
      throw new IOException("request token failed, " + e.getMessage());
    }
  }
  
  public void callAccessToken() throws IOException {
    try {
      OAuthClient client = new OAuthClient(new HttpClient3());
      OAuthAccessor accessor = getOAuthAccessor();

      accessor.requestToken = token;
      accessor.tokenSecret = tokenSecret;
      OAuthMessage message = client.getAccessToken(accessor, null, null);
      for(Entry<String, String> entry : message.getParameters()) {
        attributes.put(entry.getKey(), entry.getValue());
      }
    } catch (Exception e) {
      throw new IOException("access token failed, " + e.getMessage());
    }
  }
  
  public String getAuthorizationUrl() throws IOException {
    if (authorizationURL == null) {
      callRequestToken();
    }
    return authorizationURL;
  }
  
  public String getTokenSecret() {
    return tokenSecret;
  }

}
